package com.mti.monitor.scheduled;

import com.mti.monitor.bean.model.SysMonitorConfig;
import com.mti.monitor.enums.TaskTypeEnum;
import com.mti.monitor.service.DataMonitorService;
import com.mti.monitor.service.ServerMonitorService;
import com.mti.monitor.service.StatisticsService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.CronTask;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.annotation.PreDestroy;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledFuture;

@Component
@Configuration
@EnableScheduling
@Slf4j
public class ScheduledConfig implements SchedulingConfigurer {

    private volatile ScheduledTaskRegistrar registrar;

    private final ConcurrentHashMap<String, ScheduledFuture<?>> scheduledFutures = new ConcurrentHashMap<>();
    private final ConcurrentHashMap<String, CronTask> cronTasks = new ConcurrentHashMap<>();


    @Autowired
    private ServerMonitorService serverMonitorService;

    @Autowired
    private DataMonitorService dataMonitorService;

    @Autowired
    private StatisticsService statisticsService;


    @Override
    public void configureTasks(ScheduledTaskRegistrar registrar) {

        //设置20个线程,默认单线程,如果不设置的话，不能同时并发执行任务
        registrar.setScheduler(Executors.newScheduledThreadPool(10));
        this.registrar = registrar;
    }

    /**
     * 修改 cron 需要 调用该方法
     */
    public void refresh(List<SysMonitorConfig> tasks) {
        //取消已经删除的策略任务
        Set<String> sids = scheduledFutures.keySet();
        for (String sid : sids) {
            if (!exists(tasks, sid)) {
                scheduledFutures.get(sid).cancel(false);
            }
        }
        for (SysMonitorConfig taskEntity : tasks) {
            String expression = taskEntity.getScheduledCron();
            //计划任务表达式为空则跳过
            if (!StringUtils.hasLength(expression)) {
                continue;
            }
            //计划任务已存在并且表达式未发生变化则跳过
            if (scheduledFutures.containsKey(taskEntity.getId())
                    && cronTasks.get(taskEntity.getId()).getExpression().equals(expression)) {
                continue;
            }
            //如果策略执行时间发生了变化，则取消当前策略的任务
            if (scheduledFutures.containsKey(taskEntity.getId())) {
                scheduledFutures.get(taskEntity.getId()).cancel(false);
                scheduledFutures.remove(taskEntity.getId());
                cronTasks.remove(taskEntity.getId());
            }
            //业务逻辑处理
            CronTask task = cronTask(taskEntity, expression);

            //执行业务
            ScheduledFuture<?> future = registrar.getScheduler().schedule(task.getRunnable(), task.getTrigger());
            cronTasks.put(taskEntity.getId(), task);
            scheduledFutures.put(taskEntity.getId(), future);
        }
    }

    /**
     * 停止 cron 运行
     */
    public void stop(List<String> taskIds) {
        taskIds.forEach(id -> {
            if (scheduledFutures.containsKey(id)) {
                // mayInterruptIfRunning设成false话，不允许在线程运行时中断，设成true的话就允许。
                scheduledFutures.get(id).cancel(false);
                scheduledFutures.remove(id);
            }
        });
    }

    /**
     * 业务逻辑处理
     */
    public CronTask cronTask(SysMonitorConfig taskEntity, String expression) {
        return new CronTask(() -> {
            if (taskEntity.getTaskType().equals(TaskTypeEnum.SERVER.getType())) {
                serverMonitorService.monitorServerHeart(taskEntity.getId());
            } else if (taskEntity.getTaskType().equals(TaskTypeEnum.DATA.getType())) {
                dataMonitorService.monitorData(taskEntity.getId());
            } else if (taskEntity.getTaskType().equals(TaskTypeEnum.STATISTICS.getType())) {
                statisticsService.statisticsData(taskEntity.getId());
            } else {
                log.warn("{}监控任务{}监控类型{}错误", taskEntity.getId(), taskEntity.getTaskName(), taskEntity.getTaskType());
            }
        }, expression);
    }

    private boolean exists(List<SysMonitorConfig> tasks, String tid) {
        for (SysMonitorConfig taskEntity : tasks) {
            if (taskEntity.getId().equals(tid)) {
                return true;
            }
        }
        return false;
    }


    @PreDestroy
    public void destroy() {
        this.registrar.destroy();
    }

}